package com.autumn.zero.workflow.services.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.VariableScope;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.autumn.domain.repositories.IDefaultEntityRepository;
import com.autumn.mybatis.criterion.EntityQuery;
import com.autumn.mybatis.criterion.Query;
import com.autumn.util.DataRollbackException;
import com.autumn.util.ExceptionUtils;
import com.autumn.util.TypeUtils;
import com.autumn.util.data.DbAuditingUtils;
import com.autumn.zero.workflow.constants.ProcessDesignStatusConstants;
import com.autumn.zero.workflow.constants.ProcessExecutConstants;
import com.autumn.zero.workflow.constants.ProcessResultConstants;
import com.autumn.zero.workflow.constants.ProcessStatusConstants;
import com.autumn.zero.workflow.constants.ProcessTaskConstants;
import com.autumn.zero.workflow.entitys.AbstractWorkflowDefinition;
import com.autumn.zero.workflow.entitys.AbstractWorkflowProcess;
import com.autumn.zero.workflow.entitys.WorkflowUserTaskComplete;
import com.autumn.zero.workflow.entitys.WorkflowUserTaskWait;
import com.autumn.zero.workflow.listeners.IProcessListenerNotify;
import com.autumn.zero.workflow.listeners.ProcessListenerNotifyManager;
import com.autumn.zero.workflow.process.CustomProcessDiagramGenerator;
import com.autumn.zero.workflow.repositorys.IWorkflowUserTaskCompleteRepository;
import com.autumn.zero.workflow.repositorys.IWorkflowUserTaskWaitRepository;
import com.autumn.zero.workflow.services.IProcessService;
import com.autumn.zero.workflow.values.ProcessStartValue;
import com.autumn.zero.workflow.values.ProcessTaskCompleteValue;

/**
 * 进程抽象服务
 * 
 * @author 杨昌国 2019-01-28 14:12:08
 * @param <TWorkflowDefinition> 工作流定义类型
 * @param <TWorkflowProcess> 工作流进程类型
 */
public abstract class AbstractProcessService<TWorkflowDefinition extends AbstractWorkflowDefinition, TWorkflowProcess extends AbstractWorkflowProcess>
		implements IProcessService {

	/**
	 * 流程引擎
	 */
	@Autowired
	protected ProcessEngine processEngine;

	/**
	 * 流程监听管理
	 */
	@Autowired
	protected ProcessListenerNotifyManager processListenerNotifyManager;

	/**
	 * 获取流程定义仓储
	 * 
	 * @return
	 */
	protected abstract IDefaultEntityRepository<TWorkflowDefinition> getWorkflowDefinitionRepository();

	/**
	 * 获取流程定义类型
	 * 
	 * @return
	 */
	protected abstract Class<TWorkflowDefinition> getWorkflowDefinitionEntityClass();

	/**
	 * 获取工作流程进程仓储
	 * 
	 * @return
	 */
	protected abstract IDefaultEntityRepository<TWorkflowProcess> getWorkflowProcessRepository();

	/**
	 * 获取工作流程进程类型
	 * 
	 * @return
	 */
	protected abstract Class<TWorkflowProcess> getWorkflowProcessEntityClass();

	/**
	 * 用户待办事项仓储
	 */
	@Autowired
	protected IWorkflowUserTaskWaitRepository workflowUserTaskWaitRepository;

	/**
	 * 用户已办任务仓储
	 */
	@Autowired
	protected IWorkflowUserTaskCompleteRepository workflowUserTaskCompleteRepository;

	/**
	 * 查询流程定义
	 * 
	 * @param formType 表单类型
	 * @return
	 */
	protected TWorkflowDefinition queryWorkflowDefinitionByFormType(int formType) {
		Query query = new Query(this.getWorkflowDefinitionEntityClass());
		query.eq(AbstractWorkflowDefinition.FILED_FORM_TYPE, formType);
		TWorkflowDefinition entity = this.getWorkflowDefinitionRepository().selectFirst(query.builderSection());
		return entity;
	}

	/**
	 * 启动流程
	 */
	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public void startProcess(ProcessStartValue value) {
		ExceptionUtils.checkNotNull(value, "value");
		value.valid();
		TWorkflowDefinition workflowDefinition = this.queryWorkflowDefinitionByFormType(value.getFormType());
		if (workflowDefinition == null) {
			ExceptionUtils.throwValidationException("指定的表单类型不能为空。");
		}
		if (!workflowDefinition.getStatus().equals(ProcessDesignStatusConstants.PUBLISH)) {
			ExceptionUtils.throwValidationException("指定的流程未发布，不能启动。");
		}
		Map<String, Object> variables = value.createVariable();
		variables.put(ProcessExecutConstants.VARIABLE_PROCESS_EXECUT_RESULT, ProcessResultConstants.INITIALIZE);
		variables.put(ProcessExecutConstants.VARIABLE_FLOW_NAME, workflowDefinition.getFlowName());
		variables.put(ProcessExecutConstants.VARIABLE_PROCESS_ID, workflowDefinition.getProcessId());
		processEngine.getRuntimeService().startProcessInstanceByKey(workflowDefinition.getProcessId(), variables);
	}

	/**
	 * 创建工作流程进程
	 * 
	 * @param execution
	 * @return
	 */
	protected TWorkflowProcess createWorkflowProcess(DelegateExecution execution) {
		ExecutionEntityImpl executionEntity = (ExecutionEntityImpl) execution;
		TWorkflowProcess workflowProcess;
		try {
			workflowProcess = getWorkflowProcessEntityClass().newInstance();
		} catch (Exception e) {
			throw ExceptionUtils.throwSystemException(e.getMessage(), e);
		}
		workflowProcess.setFlowName(this.getVariable(execution, ProcessExecutConstants.VARIABLE_FLOW_NAME,
				executionEntity.getProcessDefinitionName(), String.class));
		workflowProcess.setFlowTitle(
				this.getVariable(execution, ProcessExecutConstants.VARIABLE_FLOW_TITLE, "未知标题", String.class));
		workflowProcess
				.setFormId(this.getVariable(execution, ProcessExecutConstants.VARIABLE_FORM_ID, null, Long.class));
		workflowProcess
				.setFormNo(this.getVariable(execution, ProcessExecutConstants.VARIABLE_FORM_NO, "未知单号", String.class));
		workflowProcess.setFormType(
				this.getVariable(execution, ProcessExecutConstants.VARIABLE_FORM_TYPE, null, Integer.class));
		workflowProcess.setProcessDefinitionId(execution.getProcessDefinitionId());
		workflowProcess.setProcessId(
				this.getVariable(execution, ProcessExecutConstants.VARIABLE_PROCESS_ID, "未知流程id", String.class));
		workflowProcess.setProcessInstanceId(execution.getProcessInstanceId());
		workflowProcess.setProcessResult(ProcessResultConstants.APPROVALING);
		workflowProcess.setStartDate(executionEntity.getStartTime());
		workflowProcess.setStartUserId(
				this.getVariable(execution, ProcessExecutConstants.VARIABLE_START_USER_ID, null, String.class));
		workflowProcess.setStartUserName(
				this.getVariable(execution, ProcessExecutConstants.VARIABLE_START_USER_NAME, "未知用户", String.class));
		workflowProcess.setStatus(ProcessStatusConstants.EXECUTING);
		workflowProcess.setStatusMessage("运行中");
		DbAuditingUtils.insertSetProperty(workflowProcess);
		workflowProcess.forNullToDefault();
		return workflowProcess;
	}

	/**
	 * 获取变量
	 * 
	 * @param variableScope
	 * @param name
	 * @param defaultValue
	 * @param valueClass
	 * @return
	 */
	protected final <T> T getVariable(VariableScope variableScope, String name, T defaultValue, Class<T> valueClass) {
		Object variable = variableScope.getVariable(name);
		if (variable == null) {
			return defaultValue;
		}
		return TypeUtils.toConvert(valueClass, variable);
	}

	/**
	 * 获取本地变量
	 * 
	 * @param variableScope
	 * @param name
	 * @param defaultValue
	 * @param valueClass
	 * @return
	 */
	protected final <T> T getVariableLocal(VariableScope variableScope, String name, T defaultValue,
			Class<T> valueClass) {
		Object variable = variableScope.getVariableLocal(name);
		if (variable == null) {
			return defaultValue;
		}
		return TypeUtils.toConvert(valueClass, variable);
	}

	/**
	 * 进程监听通知
	 * 
	 * @param consumer 消费
	 */
	private void processListenerNotifyCallback(Consumer<IProcessListenerNotify> consumer) {
		if (consumer == null) {
			return;
		}
		IProcessListenerNotify[] listenerNotifys = processListenerNotifyManager.toNotifys();
		for (IProcessListenerNotify processListenerNotify : listenerNotifys) {
			consumer.accept(processListenerNotify);
		}
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public AbstractWorkflowProcess startProcessEventSave(DelegateExecution execution) {
		TWorkflowProcess process = this.createWorkflowProcess(execution);
		process.valid();
		this.getWorkflowProcessRepository().insert(process);
		execution.setVariable(ProcessExecutConstants.VARIABLE_PROCESS_EXECUT_RESULT, process.getProcessResult());
		this.processListenerNotifyCallback(c -> {
			c.startProcess(process);
		});
		return process;
	}

	/**
	 * 查询工作流进程
	 * 
	 * @param processDefinitionId 工作流定义id
	 * @param processInstanceId   工作流实例id
	 * @return
	 */
	private TWorkflowProcess queryWorkflowProcess(String processDefinitionId, String processInstanceId) {
		EntityQuery<TWorkflowProcess> query = new EntityQuery<>(this.getWorkflowProcessEntityClass());
		query.eq(AbstractWorkflowProcess.FILED_PROCESS_DEFINITION_ID, processDefinitionId)
				.eq(AbstractWorkflowProcess.FILED_PROCESS_INSTANCE_ID, processInstanceId);
		TWorkflowProcess workflowProcess = query.selectByFirst(this.getWorkflowProcessRepository());
		return workflowProcess;
	}

	/**
	 * 
	 */
	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public void endProcessEventSave(DelegateExecution execution) {
		TWorkflowProcess workflowProcess = this.queryWorkflowProcess(execution.getProcessDefinitionId(),
				execution.getProcessInstanceId());
		if (workflowProcess != null) {
			Integer processResult = this.getVariable(execution, ProcessExecutConstants.VARIABLE_PROCESS_EXECUT_RESULT,
					ProcessResultConstants.UNKNOWN, Integer.class);
			workflowProcess.setEndDate(new Date());
			workflowProcess.setProcessResult(processResult);
			workflowProcess.setStatus(ProcessStatusConstants.END);
			workflowProcess.setStatusMessage("流程结束");
			this.getWorkflowProcessRepository().update(workflowProcess);
			this.processListenerNotifyCallback(c -> {
				c.endProcess(workflowProcess);
			});
		}
	}

	/**
	 * 用户待办作务事件
	 * 
	 * @param delegateTask
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public WorkflowUserTaskWait userTaskWaitEvent(DelegateTask delegateTask) {
		TWorkflowProcess workflowProcess = this.queryWorkflowProcess(delegateTask.getProcessDefinitionId(),
				delegateTask.getProcessInstanceId());
		if (workflowProcess != null) {
			WorkflowUserTaskWait workflowUserTaskWait = new WorkflowUserTaskWait();
			workflowUserTaskWait.setFlowProcessId(workflowProcess.getId());
			workflowUserTaskWait.setTaskName(delegateTask.getName());
			workflowUserTaskWait.setTaskNo(delegateTask.getId());
			workflowUserTaskWait.setUserId(delegateTask.getAssignee());
			workflowUserTaskWait.setTaskTime(delegateTask.getCreateTime());
			workflowUserTaskWait.setTaskSummary(delegateTask.getDescription());
			DbAuditingUtils.insertSetProperty(workflowUserTaskWait);
			workflowUserTaskWait.forNullToDefault();
			workflowUserTaskWaitRepository.insert(workflowUserTaskWait);
			this.processListenerNotifyCallback(c -> {
				c.userTaskWait(workflowProcess, workflowUserTaskWait);
			});
			return workflowUserTaskWait;
		}
		return null;
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public WorkflowUserTaskComplete userTaskCompleteEvent(DelegateTask delegateTask) {
		TWorkflowProcess workflowProcess = this.queryWorkflowProcess(delegateTask.getProcessDefinitionId(),
				delegateTask.getProcessInstanceId());

		if (workflowProcess == null) {
			return null;
		}
		
		WorkflowUserTaskComplete workflowUserTaskComplete = null;
		
		Integer taskResult = this.getVariableLocal(delegateTask, ProcessExecutConstants.VARIABLE_TASK_RESULT,
				ProcessTaskConstants.UNKNOWN, Integer.class);
		
		if (taskResult != null && ProcessTaskConstants.UNKNOWN != taskResult.intValue()) {
			workflowUserTaskComplete = new WorkflowUserTaskComplete();
			workflowUserTaskComplete.setFlowProcessId(workflowProcess.getId());
			workflowUserTaskComplete.setTaskName(delegateTask.getName());
			workflowUserTaskComplete.setTaskNo(delegateTask.getId());
			workflowUserTaskComplete.setUserId(delegateTask.getAssignee());
			workflowUserTaskComplete.setTaskTime(delegateTask.getCreateTime());
			workflowUserTaskComplete.setCompleteTime(new Date());
			
			workflowUserTaskComplete.setTaskResult(taskResult);
			String taskOpinion = this.getVariableLocal(delegateTask, ProcessExecutConstants.VARIABLE_TASK_OPINION, "",
					String.class);
			workflowUserTaskComplete.setTaskOpinion(taskOpinion);
			String userName = this.getVariableLocal(delegateTask, ProcessExecutConstants.VARIABLE_TASK_USER_NAME, "",
					String.class);

			workflowUserTaskComplete.setUserName(userName);
			workflowUserTaskComplete.setTaskSummary(delegateTask.getDescription());
			DbAuditingUtils.insertSetProperty(workflowUserTaskComplete);
			workflowUserTaskComplete.forNullToDefault();
			this.workflowUserTaskCompleteRepository.insert(workflowUserTaskComplete);
		}

		EntityQuery<WorkflowUserTaskWait> query = new EntityQuery<>(WorkflowUserTaskWait.class);
		query.eq(WorkflowUserTaskWait.FILED_FLOW_ID, workflowProcess.getId()).eq(WorkflowUserTaskWait.FILED_TASK_NO,
				delegateTask.getId());
		query.deleteByWhere(this.workflowUserTaskWaitRepository);
		if (workflowUserTaskComplete != null) {
			final WorkflowUserTaskComplete userTaskComplete = workflowUserTaskComplete;
			this.processListenerNotifyCallback(c -> {
				c.userTaskComplete(workflowProcess, userTaskComplete);
			});
		}
		return workflowUserTaskComplete;
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public void userTaskDeleteEvent(DelegateTask delegateTask) {

	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public void taskComplete(ProcessTaskCompleteValue value) {
		ExceptionUtils.checkNotNull(value, "value");
		value.valid();
		TaskService taskService = processEngine.getTaskService();
		List<Task> list = taskService.createTaskQuery().taskAssignee(value.getUserId()).taskId(value.getTaskId())
				.list();

		taskService.setVariableLocal(value.getTaskId(), ProcessExecutConstants.VARIABLE_TASK_RESULT,
				value.getTaskResult());
		taskService.setVariableLocal(value.getTaskId(), ProcessExecutConstants.VARIABLE_TASK_OPINION,
				value.getTaskOpinion());
		taskService.setVariableLocal(value.getTaskId(), ProcessExecutConstants.VARIABLE_TASK_USER_NAME,
				value.getUserName());

		Map<String, Object> variables = new HashMap<>();
		switch (value.getTaskResult()) {
		case ProcessTaskConstants.AGREE:
			variables.put(ProcessExecutConstants.VARIABLE_PROCESS_EXECUT_RESULT, ProcessResultConstants.AGREE);
			break;
		case ProcessTaskConstants.REFUSE:
			variables.put(ProcessExecutConstants.VARIABLE_PROCESS_EXECUT_RESULT, ProcessResultConstants.REFUSE);
		}
		String processInstanceId = null;
		for (Task task : list) {
			taskService.complete(task.getId(), variables);
			processInstanceId = task.getProcessInstanceId();
		}
		// 如果不同意
		if (!value.getTaskResult().equals(ProcessTaskConstants.AGREE) && processInstanceId != null) {
			list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
			while (list.size() > 0) {
				for (Task task : list) {
					taskService.complete(task.getId(), variables);
					// taskService.deleteTask(task.getId(), "上一节点拒绝，自动删除之后节点。");
				}
				list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
			}
		}
	}

	@Override
	public void writeFlowImageByInstanceId(String processInstanceId, OutputStream outputStream) throws IOException {
		ExceptionUtils.checkNotNull(outputStream, "outputStream");
		InputStream imageStream = null;
		try {
			imageStream = this.queryFlowImageByInstanceId(processInstanceId);
			byte[] b = new byte[4096];
			int len;
			while ((len = imageStream.read(b, 0, b.length)) != -1) {
				outputStream.write(b, 0, len);
			}
		} finally {
			IOUtils.closeQuietly(imageStream);
		}
	}

	/**
	 * 查询流程图片
	 * 
	 * @param processInstanceId 流程图实例id
	 * @return
	 * @throws IOException
	 */
	@Override
	public InputStream queryFlowImageByInstanceId(String processInstanceId) throws IOException {
		ExceptionUtils.checkNotNullOrBlank(processInstanceId, "processInstanceId");
		HistoryService historyService = processEngine.getHistoryService();
		// 获取历史流程实例
		HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
				.processInstanceId(processInstanceId).singleResult();
		if (historicProcessInstance == null) {
			ExceptionUtils.throwValidationException("指定的流程实例不存在。");
		}
		// 获取流程中已经执行的节点，按照执行先后顺序排序
		List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
				.processInstanceId(processInstanceId).orderByHistoricActivityInstanceId().asc().list();
		// 高亮已经执行流程节点ID集合
		List<String> highLightedActivitiIds = new ArrayList<>();
		for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
			highLightedActivitiIds.add(historicActivityInstance.getActivityId());
		}
		List<HistoricProcessInstance> historicFinishedProcessInstances = historyService
				.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).finished().list();

		ProcessDiagramGenerator processDiagramGenerator;
		// 如果还没完成，流程图高亮颜色为绿色，如果已经完成为红色
		if (historicFinishedProcessInstances != null && historicFinishedProcessInstances.size() > 0) {
			// 如果不为空，说明已经完成
			processDiagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
		} else {
			processDiagramGenerator = new CustomProcessDiagramGenerator();
		}
		BpmnModel bpmnModel = processEngine.getRepositoryService()
				.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
		// 高亮流程已发生流转的线id集合
		List<String> highLightedFlowIds = this.getHighLightedFlows(bpmnModel, historicActivityInstances);
		InputStream imageStream = processDiagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitiIds,
				highLightedFlowIds, "宋体", "微软雅黑", "黑体", null, 2.0);
		return imageStream;
	}

	/**
	 * 获取已经流转的线
	 * 
	 * @param bpmnModel
	 * @param historicActivityInstances
	 * @return
	 */
	private List<String> getHighLightedFlows(BpmnModel bpmnModel,
			List<HistoricActivityInstance> historicActivityInstances) {
		// 高亮流程已发生流转的线id集合
		List<String> highLightedFlowIds = new ArrayList<>();
		// 全部活动节点
		List<FlowNode> historicActivityNodes = new ArrayList<>();
		// 已完成的历史活动节点
		List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();

		for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
			FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess()
					.getFlowElement(historicActivityInstance.getActivityId(), true);
			historicActivityNodes.add(flowNode);
			if (historicActivityInstance.getEndTime() != null) {
				finishedActivityInstances.add(historicActivityInstance);
			}
		}

		FlowNode currentFlowNode = null;
		FlowNode targetFlowNode = null;
		// 遍历已完成的活动实例，从每个实例的outgoingFlows中找到已执行的
		for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
			// 获得当前活动对应的节点信息及outgoingFlows信息
			currentFlowNode = (FlowNode) bpmnModel.getMainProcess()
					.getFlowElement(currentActivityInstance.getActivityId(), true);
			List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();

			/**
			 * 遍历outgoingFlows并找到已已流转的 满足如下条件认为已已流转：
			 * 1.当前节点是并行网关或兼容网关，则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
			 * 2.当前节点是以上两种类型之外的，通过outgoingFlows查找到的时间最早的流转节点视为有效流转
			 */
			if ("parallelGateway".equalsIgnoreCase(currentActivityInstance.getActivityType())
					|| "inclusiveGateway".equalsIgnoreCase(currentActivityInstance.getActivityType())) {
				// 遍历历史活动节点，找到匹配流程目标节点的
				for (SequenceFlow sequenceFlow : sequenceFlows) {
					targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(),
							true);
					if (historicActivityNodes.contains(targetFlowNode)) {
						highLightedFlowIds.add(targetFlowNode.getId());
					}
				}
			} else {
				List<Map<String, Object>> tempMapList = new ArrayList<>();
				for (SequenceFlow sequenceFlow : sequenceFlows) {
					for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
						if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
							Map<String, Object> map = new HashMap<>();
							map.put("highLightedFlowId", sequenceFlow.getId());
							map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
							tempMapList.add(map);
						}
					}
				}
				if (tempMapList != null && tempMapList.size() > 0) {
					// 遍历匹配的集合，取得开始时间最早的一个
					long earliestStamp = 0L;
					String highLightedFlowId = null;
					for (Map<String, Object> map : tempMapList) {
						long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
						if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
							highLightedFlowId = map.get("highLightedFlowId").toString();
							earliestStamp = highLightedFlowStartTime;
						}
					}
					highLightedFlowIds.add(highLightedFlowId);
				}
			}
		}
		return highLightedFlowIds;
	}

	/**
	 * 查询流程进程实例
	 * 
	 * @param id 流程id
	 * @return
	 */
	@Override
	public AbstractWorkflowProcess queryWorkflowProcessById(Long id) {
		return this.getWorkflowProcessRepository().get(id);
	}

	/**
	 * 查询流程进程实例
	 * 
	 * @param processInstanceId 流程实例id
	 * @return
	 */
	@Override
	public AbstractWorkflowProcess queryWorkflowProcessByInstanceId(String processInstanceId) {
		EntityQuery<TWorkflowProcess> query = new EntityQuery<>(this.getWorkflowProcessEntityClass());
		query.eq(AbstractWorkflowProcess.FILED_PROCESS_INSTANCE_ID, processInstanceId);
		TWorkflowProcess workflowProcess = query.selectByFirst(this.getWorkflowProcessRepository());
		return workflowProcess;
	}
}
